package com.boot.pojo;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class BankAccount {
    private final String accountId;
    private int balance;
    private Lock lock = new ReentrantLock(true);
    private final Condition sufficientFunds = lock.newCondition();

    public BankAccount(String accountId, int balance) {
        this.accountId = accountId;
        this.balance = balance;
    }

    /**
     * 标准转账方法（会一直等待直到获取所有需要的锁）
     */
    public void transfer(BankAccount to, int amount) throws InterruptedException {
        long start = System.currentTimeMillis();
        // 获取两个账户的锁，避免死锁（通过固定的锁获取顺序）
        boolean fromLocked = false;
        boolean toLocked = false;

        try {
            // 按照账户ID顺序获取锁，避免死锁
            if (this.accountId.compareTo(to.accountId) < 0) {
                //允许中断
                this.lock.lockInterruptibly();
                fromLocked = true;
                to.lock.lockInterruptibly();
                toLocked = true;
            } else {
                to.lock.lockInterruptibly();
                toLocked = true;
                this.lock.lockInterruptibly();
                fromLocked = true;
            }

            while (balance < amount) {
                System.out.println(Thread.currentThread().getName() + ":账户" + accountId +
                        "余额不足，等待中... 当前余额：" + balance + ", 需要：" + amount);
                //释放锁并等待
                sufficientFunds.await();
            }
            this.balance -= amount;
            to.balance += amount;
            System.out.println(Thread.currentThread().getName() + "：从" + accountId +
                    "转账" + amount + "到" + to.accountId);
            System.out.println("转账后：" + this + "，" + to);

            //通知其他可能等待的线程
            sufficientFunds.signalAll();
            to.sufficientFunds.signalAll();
        } finally {
            if (fromLocked) {
                this.lock.unlock();
            }
            if (toLocked) {
                to.lock.unlock();
            }
        }
    }

    /**
     * 尝试转账（带超时）
     */
    public boolean tryTransfer(BankAccount to, int amount, long timeout, TimeUnit unit) throws InterruptedException {
        boolean fromLocked = false;
        boolean toLocked = false;

        long nanosToWait = unit.toNanos(timeout);
        long endTime = System.nanoTime() + nanosToWait;

        try {
            //尝试获取第一个锁(带超时)
            if (this.accountId.compareTo(to.accountId) < 0) {
                fromLocked = this.lock.tryLock(nanosToWait, TimeUnit.NANOSECONDS);
                if (!fromLocked) return false;

                nanosToWait = endTime - System.nanoTime();
                toLocked = to.lock.tryLock(nanosToWait, TimeUnit.NANOSECONDS);
                if (!toLocked) return false;
            } else {
                toLocked = to.lock.tryLock(nanosToWait, TimeUnit.NANOSECONDS);
                if (!toLocked) return false;

                nanosToWait = endTime - System.nanoTime();
                fromLocked = this.lock.tryLock(nanosToWait, TimeUnit.NANOSECONDS);
                if (!fromLocked) return false;
            }
            while (balance < amount) {
                if (nanosToWait <= 0) {
                    return false; // 超时
                }
                System.out.println(Thread.currentThread().getName() + ":账户" + accountId +
                        "余额不足，等待中... 当前余额：" + balance + ", 需要：" + amount);
                nanosToWait = sufficientFunds.awaitNanos(nanosToWait);
            }
            // 执行转账
            this.balance -= amount;
            to.balance += amount;
            System.out.println(Thread.currentThread().getName() + ": [尝试]从" + accountId +
                    "转账" + amount + "到" + to.accountId + "成功");
            System.out.println("转账后: " + this + ", " + to);
            // 通知其他可能等待的线程
            sufficientFunds.signalAll();
            to.sufficientFunds.signalAll();

            return true;
        } finally {
            if (fromLocked) {
                this.lock.unlock();
            }
            if (toLocked) {
                to.lock.unlock();
            }
        }
    }

    @Override
    public String toString() {
        return "账户" + accountId + "余额: " + balance;
    }
}
